import 'package:flutter/material.dart';

abstract class LoadingTable<B> extends StatefulWidget {

  LoadingTable({Key key, this.name, this.title}) : super(key : key);

  String name;
  String title;
  _LoadingTableState _loadingTableState;

  GlobalKey<_LoadingTableState> loadingKey = new GlobalKey<_LoadingTableState>();

  @override
  _LoadingTableState createState() {
    _loadingTableState = new _LoadingTableState();
    return _loadingTableState;
  }

  void loadingData();

  Widget addData() {
    return Scaffold(
        appBar: new AppBar(
            title: const Text("add data form!")
        ),
        body: const Center(
          child: const Text("add data from!"),
        )
    );
  }

  Widget editData(TableBeanVo tableBeanVo) {
    return Scaffold(
        appBar: new AppBar(
            title: const Text("eidt data form!")
        ),
        body: const Center(
          child: const Text("eidt data from!"),
        )
    );
  }

  void setData(List<B> data) {
    List<TableBeanVo> tableBeanVoList = data.map((b) {
      TableBeanVo vo = new TableBeanVo(b, false);
      return vo;
    }).toList();
    _loadingTableState.setData(tableBeanVoList);
  }

  List<Widget> celles(B bean);

  List<SortDataColumn> sortDataColumns();

}

class _LoadingTableState extends State<LoadingTable> {
  int _rowsPerPage = PaginatedDataTable.defaultRowsPerPage;
  int _sortColumnIndex;
  bool _sortAscending = false;
  LoadingTableDataSource _dessertsDataSource;
  bool isLoaded = false;

  void _sort<T>(Comparable<T> getField(TableBeanVo d), int columnIndex, bool ascending) {
    _dessertsDataSource._sort<T>(getField, ascending);
    setState(() {
      _sortColumnIndex = columnIndex;
      _sortAscending = ascending;
    });
  }

  @override
  void initState() {
    super.initState();
    _dessertsDataSource = new LoadingTableDataSource(widget, new List<TableBeanVo>());
    _loadData();
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(title: new Text(widget.title)),
      body:_doBody(),
    );
  }

  Widget _doBody() {
    if (isLoaded) {
      return new ListView(
          padding: const EdgeInsets.all(20.0),
          children: <Widget>[
            new PaginatedDataTable(
                header: new Text('${r'${'}widget.name}'),
                rowsPerPage: _rowsPerPage,
                onRowsPerPageChanged: (int value) { setState(() { _rowsPerPage = value; }); },
                sortColumnIndex: _sortColumnIndex,
                sortAscending: _sortAscending,
                onSelectAll: _dessertsDataSource._selectAll,
                columns: widget.sortDataColumns().map<DataColumn>((sortDataColumn) {
                  return new DataColumn(
                      label: sortDataColumn.label,
                      tooltip: sortDataColumn.tooltip??"",
                      numeric: sortDataColumn.numeric??false,
                      onSort: (int columnIndex, bool ascending) => _sort(sortDataColumn.getField, columnIndex, ascending)
                  );
                }).toList(),
                source: _dessertsDataSource,
                actions: <Widget>[
                  new IconButton(onPressed: (){
                    Widget addWidget = widget.addData();
                    if (addWidget == null) return;
                    Navigator.of(context).push(new MaterialPageRoute(
                        builder: (BuildContext buildContext) {
                          return addWidget;
                        }
                    ));
                  }, icon: const Icon(Icons.add, color: Colors.blueAccent,), ),

                  new IconButton(onPressed: (){
                    List<TableBeanVo> selectedDatas = _dessertsDataSource.selectedDatas;
                    if (selectedDatas != null && selectedDatas.length > 0) {
                      Widget editWidget = widget.editData(selectedDatas[0]);
                      if (editWidget == null) return;
                      Navigator.of(context).push(new MaterialPageRoute(
                          builder: (BuildContext buildContext) {
                            return editWidget;
                          }
                      ));
                    }
                  }, icon: const Icon(Icons.edit, color: Colors.blueAccent), ),

                  new IconButton(onPressed: (){}, icon: const Icon(Icons.delete, color: Colors.blueAccent,), ),
                ],
            )
          ]
      );
    } else {
      return new Center(
        child: new CircularProgressIndicator(),
      );
    }
  }

  void _loadData() {
    widget.loadingData();
  }

  void setData(List<TableBeanVo> tableBeanVoList) {
    _dessertsDataSource.setDatas(tableBeanVoList);
    setState(() {
      isLoaded = true;
    });
  }
}

class LoadingTableDataSource extends DataTableSource {

  LoadingTableDataSource(LoadingTable loadingTable, List<TableBeanVo> tableBeanList){

    this._loadingTable = loadingTable;
    this._tableBeanList = tableBeanList;
  }

  List<TableBeanVo> _tableBeanList = null;
  LoadingTable _loadingTable;

  void _sort<T>(Comparable<T> getField(TableBeanVo d), bool ascending) {
    _tableBeanList.sort((TableBeanVo a, TableBeanVo b) {
      if (!ascending) {
        final TableBeanVo c = a;
        a = b;
        b = c;
      }
      final Comparable<T> aValue = getField(a);
      final Comparable<T> bValue = getField(b);
      return Comparable.compare(aValue, bValue);
    });
    notifyListeners();
  }

  int _selectedCount = 0;

  @override
  DataRow getRow(int index) {
    assert(index >= 0);
    if (index >= _tableBeanList.length)
      return null;
    final TableBeanVo beanVo = _tableBeanList[index];
    return new DataRow.byIndex(
        index: index,
        selected: beanVo.selected,
        onSelectChanged: (bool value) {
          if (beanVo.selected != value) {
            _selectedCount += value ? 1 : -1;
            assert(_selectedCount >= 0);
            beanVo.selected = value;
            notifyListeners();
          }
        },
        cells: _loadingTable.celles(beanVo.bean).map<DataCell>((widget) {
          return new DataCell(widget);
        }).toList()
    );
  }

  @override
  int get rowCount => _tableBeanList.length;

  @override
  bool get isRowCountApproximate => false;

  @override
  int get selectedRowCount => _selectedCount;

  void _selectAll(bool checked) {
    for (TableBeanVo vo in _tableBeanList)
      vo.selected = checked;
    _selectedCount = checked ? _tableBeanList.length : 0;
    notifyListeners();
  }

  void setDatas(List<TableBeanVo> tableBeanVoList) {
    this._tableBeanList = tableBeanVoList;
//    notifyListeners();
  }

  List<TableBeanVo> get selectedDatas {
    List<TableBeanVo> selectedDatas = new List();
    print("sfdafafdadfadfa");
    for (TableBeanVo vo in _tableBeanList) {
      if (vo.selected) {
        selectedDatas.add(vo);
      }
    }
    return selectedDatas;
  }
}

class TableBeanVo<T> {

  TableBeanVo(this.bean, this.selected);

  T bean;
  bool selected = false;
}

typedef Comparable<T> GetField<T>(TableBeanVo tableBeanVo);

class SortDataColumn<T> extends DataColumn {

  SortDataColumn.sort({
    Widget label,
    String tooltip,
    bool numeric,
    DataColumnSortCallback onSort,
    this.getField,
  }): super(label: label, tooltip: tooltip, numeric: numeric, onSort: onSort);

  GetField<T> getField;

}